/*
 * Created on 2005-3-3
 */
package com.hd123.rumba.util;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.SQLException;
import java.util.Calendar;
import java.util.Date;
import java.util.Enumeration;
import java.util.GregorianCalendar;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.Map.Entry;

import net.sf.hibernate.HibernateException;
import net.sf.hibernate.id.UUIDGenerator;
import net.sf.hibernate.id.UUIDHexGenerator;

import com.hd123.rumba.exception.BusinessException;
import com.hd123.rumba.exception.StringTooLongException;
import com.hd123.rumba.runtime.FormatSettings;

/**
 * @author caili
 */
public class StringUtil {
  public static final UUIDGenerator uuidGenerator = new UUIDHexGenerator();
  public static final String SYSTEM_ENCODING = "GBK";
  public static final String HEX_CODE_LOWER = "0123456789abcdef";
  public static final String HEX_CODE_UPPER = "0123456789ABCDEF";
  public static String ENCODING_CHARSET = SYSTEM_ENCODING;
  public static final String UnicodeToHtmlMapping[] = {
      "&nbsp;", "&iexcl;", "&cent;", "&pound;", "&curren;", "&yen;", "&brkbar;", "&sect;", "&uml;",
      "&copy;", "&ordf;", "&laquo;", "&not;", "&shy;", "&reg;", "&hibar;", "&deg;", "&plusmn;",
      "&sup2;", "&sup3;", "&acute;", "&micro;", "&para;", "&middot;", "&cedil;", "&sup1;",
      "&ordm;", "&raquo;", "&frac14;", "&frac12;", "&frac34;", "&iquest;", "&Agrave;", "&Aacute;",
      "&Acirc;", "&Atilde;", "&Auml;", "&Aring;", "&AElig;", "&Ccedil;", "&Egrave;", "&Eacute;",
      "&Ecirc;", "&Euml;", "&Igrave;", "&Iacute;", "&Icirc;", "&Iuml;", "&Dstrok;", "&Ntilde;",
      "&Ograve;", "&Oacute;", "&Ocirc;", "&Otilde;", "&Ouml;", "&times;", "&Oslash;", "&Ugrave;",
      "&Uacute;", "&Ucirc;", "&Uuml;", "&Yacute;", "&THORN;", "&szlig;", "&agrave;", "&aacute;",
      "&acirc;", "&atilde;", "&auml;", "&aring;", "&aelig;", "&ccedil;", "&egrave;", "&eacute;",
      "&ecirc;", "&euml;", "&igrave;", "&iacute;", "&icirc;", "&iuml;", "&eth;", "&ntilde;",
      "&ograve;", "&oacute;", "&ocirc;", "&otilde;", "&ouml;", "&divide;", "&oslash;", "&ugrave;",
      "&uacute;", "&ucirc;", "&uuml;", "&yacute;", "&thorn;", "&yuml;" };

  /**
   * 复制字符串s若干次
   * 
   * @param s
   * @param times
   * @return
   */
  public static String duplicate(String s, int times) {
    StringBuffer sb = new StringBuffer();
    for (int i = 0; i < times; ++i)
      sb.append(s);
    return sb.toString();
  }

  public static String lpad(String s, char c, int length) {
    int times = length - s.length();
    return duplicate(new Character(c).toString(), times) + s;
  }

  public static String rpad(String s, char c, int length) {
    int times = length - s.length();
    return s + duplicate(new Character(c).toString(), times);
  }

  /**
   * 将Hashtable h的条目组成一个字符串, 每行前加缩进字符串indent, 行以lineFeed字符结尾
   * 
   * @param h
   * @param indent
   * @param lineFeed
   * @return
   */
  public static String printAll(Hashtable h, String indent, String lineFeed) {
    StringBuffer sb = new StringBuffer(h.size());
    Enumeration keys = h.keys();
    if (keys.hasMoreElements())
      while (keys.hasMoreElements()) {
        String key = (String) keys.nextElement();
        sb.append(indent + key + "=" + h.get(key) + "(" + h.get(key).getClass().getName() + ")"
            + lineFeed);
      }
    else
      sb.append(indent + "(no entries)" + lineFeed);
    return sb.toString();
  }

  public static String printAll(Map h, String indent, String lineFeed) {
    StringBuffer sb = new StringBuffer(h.size());
    Iterator entries = h.entrySet().iterator();
    if (entries.hasNext())
      while (entries.hasNext()) {
        Entry entry = (Entry) entries.next();
        Object key = entry.getKey();
        Object value = entry.getValue();
        sb.append(indent + key + "="
            + (value == null ? "null" : (value + "(" + value.getClass().getName() + ")"))
            + lineFeed);
      }
    else
      sb.append(indent + "(no entries)" + lineFeed);
    return sb.toString();
  }

  /**
   * 将一个URL按GB2312解码
   * 
   * @param s
   * @return
   */
  public static String decodePathInfo(String s) {
    return decodePathInfo(s, ENCODING_CHARSET);
  }

  /**
   * 将一个URL按encodingCharset解码
   * 
   * @param s
   * @param encodingCharset
   * @return
   */
  public static String decodePathInfo(String s, String encodingCharset) {
    if (s == null)
      return null;
    int i = s.length();
    String s2 = null;
    byte abyte0[] = new byte[i];
    int j = 0;
    for (int k = 0; k < i; k++) {
      char c = s.charAt(k);
      if (c == '%')
        if (k + 2 < i) {
          c = s.charAt(++k);
          int l = "0123456789abcdef".indexOf(c);
          if (l < 0) {
            l = "0123456789ABCDEF".indexOf(c);
            if (l < 0)
              return null;
          }
          c = s.charAt(++k);
          int i1 = "0123456789abcdef".indexOf(c);
          if (i1 < 0) {
            i1 = "0123456789ABCDEF".indexOf(c);
            if (i1 < 0)
              return null;
          }
          c = (char) (l << 4 | i1);
        } else {
          return null;
        }
      abyte0[j++] = (byte) c;
    }

    try {
      s2 = new String(abyte0, 0, j, encodingCharset);
    } catch (UnsupportedEncodingException unsupportedencodingexception) {
      s2 = null;
    }
    return s2;
  }

  /**
   * 将URL按GB2312编码
   * 
   * @param s
   * @return
   */
  public static String encodePathInfo(String s) {
    StringBuffer stringbuffer = new StringBuffer();
    encodePathInfo(s, stringbuffer);
    return stringbuffer.toString();
  }

  /**
   * 将URL按encodingCharset编码
   * 
   * @param s
   * @return
   */
  public static String encodePathInfo(String s, String encodingCharset) {
    StringBuffer stringbuffer = new StringBuffer();
    encodePathInfo(s, stringbuffer, encodingCharset);
    return stringbuffer.toString();
  }

  private static void encodePathInfo(String s, StringBuffer stringbuffer) {
    encodePathInfo(s, stringbuffer, ENCODING_CHARSET);
  }

  private static void encodePathInfo(String s, StringBuffer stringbuffer, String encodingCharset) {
    byte abyte0[] = null;
    try {
      abyte0 = s.getBytes(encodingCharset);
    } catch (UnsupportedEncodingException unsupportedencodingexception) {
      return;
    }
    int i = abyte0.length;
    for (int j = 0; j < i; j++) {
      byte byte0 = abyte0[j];
      if (byte0 == 45 || byte0 == 95 || byte0 >= 48 && byte0 <= 57 || byte0 >= 65 && byte0 <= 90
          || byte0 >= 97 && byte0 <= 122) {
        stringbuffer.append((char) byte0);
      } else {
        stringbuffer.append('%');
        byte byte1 = byte0;
        stringbuffer.append("0123456789abcdef".charAt(byte1 >>> 4 & 0xf));
        stringbuffer.append("0123456789abcdef".charAt(byte1 & 0xf));
      }
    }

  }

  /**
   * 使用MultipartRequest得到的上传的临时文件名以一个随机数为后缀 此函数截取除去此后缀的文件名.
   * 
   * @param s
   * @return
   */
  public static String extractFileName(String s) {
    return s.substring(0, s.lastIndexOf("."));
  }

  public static String toUtf8String(String s) {
    StringBuffer sb = new StringBuffer();
    for (int i = 0; i < s.length(); i++) {
      char c = s.charAt(i);
      if (c >= 0 && c <= 255) {
        sb.append(c);
      } else {
        byte[] b;
        try {
          b = String.valueOf(c).getBytes("utf-8");
        } catch (Exception ex) {
          System.out.println(ex);
          b = new byte[0];
        }
        for (int j = 0; j < b.length; j++) {
          int k = b[j];
          if (k < 0)
            k += 256;
          sb.append("%" + Integer.toHexString(k).toUpperCase());
        }
      }
    }
    return sb.toString();
  }

  public static String stringToHtml(String s) {
    if (s == null)
      return "";
    StringBuffer stringbuffer = new StringBuffer();
    int i = s.length();
    for (int j = 0; j < i; j++) {
      char c = s.charAt(j);
      switch (c) {
      case 60: // '<'
        stringbuffer.append("&lt;");
        break;

      case 62: // '>'
        stringbuffer.append("&gt;");
        break;

      case 38: // '&'
        stringbuffer.append("&amp;");
        break;

      case 34: // '"'
        stringbuffer.append("&quot;");
        break;

      case 8364:
        stringbuffer.append("&#8364;");
        break;
      case 32:
        stringbuffer.append("&nbsp;");
        break;
      default:
        if (c < '\240' || c > '\377') {
          stringbuffer.append(c);
        } else {
          c -= '\240';
          stringbuffer.append(UnicodeToHtmlMapping[c]);
        }
        break;
      }
    }

    return stringbuffer.toString();
  }

  public static String stringToXml(String s) {
    StringBuffer stringbuffer = new StringBuffer();
    int i = s.length();
    for (int j = 0; j < i; j++) {
      char c = s.charAt(j);
      switch (c) {
      case 60: // '<'
        stringbuffer.append("&lt;");
        break;

      case 62: // '>'
        stringbuffer.append("&gt;");
        break;

      case 38: // '&'
        stringbuffer.append("&amp;");
        break;

      case 39: // '\''
        stringbuffer.append("&apos;");
        break;

      case 34: // '"'
        stringbuffer.append("&quot;");
        break;

      case 35: // '#'
      case 36: // '$'
      case 37: // '%'
      case 40: // '('
      case 41: // ')'
      case 42: // '*'
      case 43: // '+'
      case 44: // ','
      case 45: // '-'
      case 46: // '.'
      case 47: // '/'
      case 48: // '0'
      case 49: // '1'
      case 50: // '2'
      case 51: // '3'
      case 52: // '4'
      case 53: // '5'
      case 54: // '6'
      case 55: // '7'
      case 56: // '8'
      case 57: // '9'
      case 58: // ':'
      case 59: // ';'
      case 61: // '='
      default:
        stringbuffer.append(c);
        break;
      }
    }

    return stringbuffer.toString();
  }

  public static String stringToJS(String s) {
    StringBuffer stringbuffer = new StringBuffer();
    int i = s.length();
    for (int j = 0; j < i; j++) {
      char c = s.charAt(j);
      switch (c) {
      case 39: // '''
        stringbuffer.append("\\'");
        break;

      case 34: // '"'
        stringbuffer.append("\\\"");
        break;

      case 92: // '\'
        stringbuffer.append("\\\\");
        break;

      default:
        stringbuffer.append(c);
        break;
      }
    }
    return stringbuffer.toString();
  }

  public static String stringToWml(String s) {
    StringBuffer stringbuffer = new StringBuffer();
    int i = s.length();
    for (int j = 0; j < i; j++) {
      char c = s.charAt(j);
      switch (c) {
      case 60: // '<'
        stringbuffer.append("&lt;");
        break;

      case 62: // '>'
        stringbuffer.append("&gt;");
        break;

      case 38: // '&'
        stringbuffer.append("&amp;");
        break;

      case 39: // '\''
        stringbuffer.append("&apos;");
        break;

      case 34: // '"'
        stringbuffer.append("&quot;");
        break;

      case 36: // '$'
        stringbuffer.append("$$");
        break;

      case 35: // '#'
      case 37: // '%'
      case 40: // '('
      case 41: // ')'
      case 42: // '*'
      case 43: // '+'
      case 44: // ','
      case 45: // '-'
      case 46: // '.'
      case 47: // '/'
      case 48: // '0'
      case 49: // '1'
      case 50: // '2'
      case 51: // '3'
      case 52: // '4'
      case 53: // '5'
      case 54: // '6'
      case 55: // '7'
      case 56: // '8'
      case 57: // '9'
      case 58: // ':'
      case 59: // ';'
      case 61: // '='
      default:
        stringbuffer.append(c);
        break;
      }
    }

    return stringbuffer.toString();
  }

  public static String firstUpperCase(String s) {
    char[] ca = s.toCharArray();
    ca[0] = Character.toUpperCase(ca[0]);
    return new String(ca);
  }

  public static String increaseString(String s) throws StringIndexOutOfBoundsException {
    BigInteger i = new BigInteger(s);
    i = i.add(BigInteger.ONE);
    String result = lpad(i.toString(), '0', s.length());
    if (result.length() > s.length())
      throw new StringIndexOutOfBoundsException("无法取得" + s + "的下一个字符串");
    return result;
  }

  public static int qpcStrToQpc(String exp) {
    int result = 1;
    StringTokenizer st = new StringTokenizer(exp, "*");
    while (st.hasMoreElements()) {
      String p = (String) st.nextElement();
      result = result * Integer.parseInt(p.trim());
    }
    return result;
  }

  public static final int ALIGN_LEFT = 0;
  public static final int ALIGN_CENTER = 1;
  public static final int ALIGN_RIGHT = 2;

  public static String pad(String s, char c, int length, int align) {
    s = s == null ? "" : s;
    String result = s;
    int len = length - s.length();
    if (len > 0)
      if (align == ALIGN_LEFT) {
        result = s + duplicate(new Character(c).toString(), len);
      } else if (align == ALIGN_RIGHT) {
        result = duplicate(new Character(c).toString(), len) + s;
      } else {
        int left = len / 2;
        int right = len - left;
        result = duplicate(new Character(c).toString(), left) + s
            + duplicate(new Character(c).toString(), right);
      }
    return result;
  }

  /**
   * 如果s超出length, 则截断到length
   * 
   * @param s
   * @param c
   * @param length
   * @param align
   * @return
   */
  public static String padx(String s, char c, int length, int align) {
    String result = pad(s, c, length, align);
    try {
      result = truncate(result, length, true);
    } catch (StringTooLongException e) {
      ;
    }
    return result;
  }

  public static BigDecimal StringToBigDecimal(String s) throws NumberFormatException {
    if (s == null || s.trim().length() == 0)
      return null;
    else
      return new BigDecimal(s);
  }

  public static Integer StringToInteger(String s) throws NumberFormatException {
    if (s == null || s.trim().length() == 0)
      return null;
    else
      return new Integer(s);
  }

  public static String encodeFileName(String fileName) {
    String s = encodePathInfo(fileName, "utf-8");
    s = s.replaceAll("%2f", "/");
    s = s.replaceAll("%2e", ".");
    return s;
  }

  public static String createUuid() throws BusinessException, HibernateException {
    try {
      return (String) uuidGenerator.generate(null, null);
    } catch (SQLException ex) {
      throw new BusinessException(ex.getMessage());
    }

  }

  /**
   * 将d的field部分添加amount. 如果d==null, 返回null. field取值为Calendar中定义的值.
   * 
   * @param d
   * @param part
   * @param days
   * @return
   */
  public static Date addDate(Date d, int field, int amount) {
    if (d == null)
      return null;
    Calendar c = new GregorianCalendar();
    c.setTime(d);
    c.add(field, amount);
    return c.getTime();
  }

  /**
   * 将date截取到日
   * 
   * @param date
   * @return
   */
  public static Date truncateToDate(Date date) {
    if (date == null)
      return null;
    Calendar c = new GregorianCalendar();
    c.setTime(date);
    int y = c.get(Calendar.YEAR), m = c.get(Calendar.MONTH), d = c.get(Calendar.DAY_OF_MONTH);
    c.clear();
    c.set(y, m, d);
    return c.getTime();
  }

  public static boolean hasTimePart(Date date) {
    return date.equals(truncateToDate(date));
  }

  public static String truncate(String s, int length, boolean autoTruncate)
      throws StringTooLongException {
    if (s.getBytes().length > length) {
      if (!autoTruncate)
        throw new StringTooLongException("\"" + s + "\"的长度超过了最大限制" + length);
      s = new String(s.getBytes(), 0, length);
      if (s.getBytes().length > length) {
        s = new String(s.getBytes(), 0, length - 1);
      }
    }
    return s;
  }

  public static String truncate(String s, int length) throws StringTooLongException {
    return truncate(s, length, FormatSettings.autoTruncate);
  }

  public static String truncate(String s, int length, String tag, String name)
      throws StringTooLongException {
    try {
      s = truncate(s, length);
    } catch (StringTooLongException e) {
      throw new StringTooLongException(name + "的长度超过了最大限制" + length, tag);
    }
    return s;
  }

  /**
   * 将输入的形如a, b, c的字符串s构造成('a', 'b', 'c'), 如果inputDelimiter=",",
   * outputDelimiter="'"的话. inputDelimiter不能为空, outputDelimiter可以为空
   * 
   * @param s
   * @param delimiter
   * @return
   */
  public static String StringToInString(String s, String inputDelimiter, String outputDelimiter) {
    if (s == null)
      return null;
    StringBuffer sb = new StringBuffer();
    StringTokenizer st = new StringTokenizer(s.trim(), inputDelimiter);
    boolean isFirst = true;
    while (st.hasMoreTokens()) {
      if (!isFirst)
        sb.append(",");
      String t = st.nextToken();
      if (outputDelimiter != null) {
        t = outputDelimiter + t + outputDelimiter;
      }
      sb.append(t);
      isFirst = false;
    }
    if (sb.length() > 0)
      return "(" + sb.toString() + ")";
    else
      return null;
  }

  /**
   * 将字符串数组拼成类似于('a', 'b', 'c')格式的字符串。
   * 
   * @param ss
   * @param delimiter
   * @return
   */
  public static String ArrayToInString(String[] ss, String delimiter) {
    if (ss == null)
      return null;
    StringBuffer sb = new StringBuffer();
    for (int i = 0; i < ss.length; i++) {
      if (i == 0)
        sb.append(delimiter + ss[i] + delimiter);
      else
        sb.append("," + delimiter + ss[i] + delimiter);
    }
    if (sb.length() > 0)
      return "(" + sb.toString() + ")";
    else
      return null;
  }

  /**
   * 将由delimiter分隔的字符串分解成一个字符串数组. 如果s==null, 返回null. <br>
   * 可供SQLSubquery使用: sq.addWhere("field in ?", breakString(aString, ","));
   * 
   * @param s
   * @param delimiter
   * @return
   */
  public static Object[] breakString(String s, String delimiter) {
    if (s == null)
      return null;
    StringTokenizer st = new StringTokenizer(s.trim(), delimiter);
    int count = st.countTokens();
    if (count == 0)
      return null;
    Object[] result = new Object[count];
    for (int i = 0; st.hasMoreTokens(); result[i++] = ((String) st.nextToken()).trim())
      ;
    return result;
  }

  public static int compareGB2312(String a, String b) {
    try {
      byte[] ba = a.getBytes("gb2312");
      byte[] bb = b.getBytes("gb2312");
      for (int i = 0; i < ba.length; ++i) {
        if (i >= bb.length)
          return 1;
        if (ba[i] < bb[i])
          return -1;
        if (ba[i] > bb[i])
          return 1;
      }
      return 0;
    } catch (UnsupportedEncodingException e) {
      return a.compareTo(b);
    }
  }

  /**
   * 返回两个时间的天数差。
   * 
   * @author kevin chen
   */
  public static int getDayBetween(Calendar c1, Calendar c2) {
    int day = 0;
    boolean changed = false;
    if (c1.after(c2)) {
      Date date = c1.getTime();
      c1.setTime(c2.getTime());
      c2.setTime(date);
      changed = true;
    }
    int endyear = c2.get(Calendar.YEAR);
    int startyear = c1.get(Calendar.YEAR);
    if (endyear == startyear) {
      day = c2.get(Calendar.DAY_OF_YEAR) - c1.get(Calendar.DAY_OF_YEAR);
    } else {
      day = c2.get(Calendar.DAY_OF_YEAR);
      c2.set(Calendar.MONTH, Calendar.DECEMBER);
      c2.set(Calendar.DAY_OF_MONTH, 31);
      endyear--;
      c2.set(Calendar.YEAR, endyear);
      while (endyear > startyear) {
        day += c2.get(Calendar.DAY_OF_YEAR);
        endyear--;
        c2.set(Calendar.YEAR, endyear);
      }
      day += c2.get(Calendar.DAY_OF_YEAR) - c1.get(Calendar.DAY_OF_YEAR);
    }
    if (!changed)
      day = -day;
    return day;
  }

  /**
   * @param str
   *          待截取的字符串
   * @param len
   *          每行的长度，多于这个长度自动换行
   * @returnv
   */
  public static String cutStr(String str, int len) {
    String s = "";
    int last = (str.length() / len) * len;
    for (int i = 0; i < str.length(); i++) {
      int r = (i + 1) % len;
      if (i != 0 && i < last) {
        if (r == 0) {
          // 如果str的长度正好是len的整数倍，则最后一个整串不换行
          if (i + 1 < str.length()) {
            s += str.substring(i + 1 - len, i + 1) + "\r";
          } else {
            s += str.substring(i + 1 - len, i + 1);
          }
        }
      } else if (i >= last) {
        s += str.substring(i, str.length());
        break;
      }
    }
    return s;
  }

  /**
   * @param str
   *          待截取的字符串
   * @param len
   *          每行的长度，多于这个长度自动换
   * @param max
   *          输出字符串最大的长度
   * @return 截取字符串并限制字符串长度，多于给定的长度＋...
   */
  public static String cutStr(String str, int len, int max) {
    String s = "";
    String sheng = "";
    if (str.length() > max) {
      str = str.substring(0, max);
      sheng = "...";
    }
    int last = (str.length() / len) * len;
    for (int i = 0; i < str.length(); i++) {
      int r = (i + 1) % len;
      if (i != 0 && i < last) {
        if (r == 0) {
          s += str.substring(i + 1 - len, i + 1) + "\r";
        }
      } else if (i >= last) {
        s += str.substring(i, str.length());
        break;
      }
    }
    return s + sheng;

  }

}
